home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / test.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  5KB  |  311 lines

  1. /* test - test conditions        Author: Erik Baalbergen */
  2.  
  3. /* Test-    version 7-like test(1).
  4.  *
  5.  * Grammar:    expr    ::= bexpr | bexpr "-o" expr ;
  6.  *        bexpr    ::= primary | primary "-a" bexpr ;
  7.  *        primary    ::= unary-operator operand
  8.  *            | operand binary-operator operand
  9.  *            | operand
  10.  *            | "(" expr ")"
  11.  *            | "!" expr
  12.  *            ;
  13.  *        unary-operator ::= "-r"|"-w"|"-f"|"-d"|"-s"|"-t"|"-z"|"-n";
  14.  *        binary-operator ::= "="|"!="|"-eq"|"-ne"|"-ge"|"-gt"|"-le"|"-lt";
  15.  *        operand ::= <any legal UNIX file name>
  16.  *
  17.  * Author:    Erik Baalbergen    erikb@cs.vu.nl
  18.  *
  19.  * History:    Fix Bert Reuling #571 (03/09/89 FVK)    bert@kyber.UUCP
  20.  *
  21.  *         Add Jeroen van der Pluijm  09/25/89 jeroen@minixug.nluug.nl
  22.  *            Enabled linking to /usr/bin/[ so you cn use structures
  23.  *            like:
  24.  *                if [ -f ./test.c ]
  25.  *            and so on. Also added checking of argv[0] to see if it
  26.  *            is '[' and the last argument if it is ']'.
  27.  *
  28.  *        Mod Fred van Kempen 09/27/89 waltje@minixug.nluug.nl
  29.  *            Adapted source to MINIX Style Sheet.
  30.  *
  31.  *        Mod Bruce Evans 09/27/89 evans@ditsyda.oz.au
  32.  *            Allow whitespace in numbers.
  33.  *            Deleted bloat from single use of stdio (fprintf).
  34.  */
  35.  
  36. #include <sys/types.h>
  37. #include <sys/stat.h>
  38. #include <sgtty.h>
  39.  
  40. #define EOI    0
  41. #define FILRD    1
  42. #define FILWR    2
  43. #define FILND    3
  44. #define FILID    4
  45. #define FILGZ    5
  46. #define FILTT    6
  47. #define STZER    7
  48. #define STNZE    8
  49. #define STEQL    9
  50. #define STNEQ    10
  51. #define INTEQ    11
  52. #define INTNE    12
  53. #define INTGE    13
  54. #define INTGT    14
  55. #define INTLE    15
  56. #define INTLT    16
  57. #define UNEGN    17
  58. #define BAND    18
  59. #define BOR    19
  60. #define LPAREN    20
  61. #define RPAREN    21
  62. #define OPERAND    22
  63.  
  64. #define UNOP    1
  65. #define BINOP    2
  66. #define BUNOP    3
  67. #define BBINOP    4
  68. #define PAREN    5
  69.  
  70. struct op {
  71.   char *op_text;
  72.   short op_num, op_type;
  73. } ops[] = {
  74.  
  75.   {
  76.     "-r", FILRD, UNOP
  77.   },
  78.   {
  79.     "-w", FILWR, UNOP
  80.   },
  81.   {
  82.     "-f", FILND, UNOP
  83.   },
  84.   {
  85.     "-d", FILID, UNOP
  86.   },
  87.   {
  88.     "-s", FILGZ, UNOP
  89.   },
  90.   {
  91.     "-t", FILTT, UNOP
  92.   },
  93.   {
  94.     "-z", STZER, UNOP
  95.   },
  96.   {
  97.     "-n", STNZE, UNOP
  98.   },
  99.   {
  100.     "=", STEQL, BINOP
  101.   },
  102.   {
  103.     "!=", STNEQ, BINOP
  104.   },
  105.   {
  106.     "-eq", INTEQ, BINOP
  107.   },
  108.   {
  109.     "-ne", INTNE, BINOP
  110.   },
  111.   {
  112.     "-ge", INTGE, BINOP
  113.   },
  114.   {
  115.     "-gt", INTGT, BINOP
  116.   },
  117.   {
  118.     "-le", INTLE, BINOP
  119.   },
  120.   {
  121.     "-lt", INTLT, BINOP
  122.   },
  123.   {
  124.     "!", UNEGN, BUNOP
  125.   },
  126.   {
  127.     "-a", BAND, BBINOP
  128.   },
  129.   {
  130.     "-o", BOR, BBINOP
  131.   },
  132.   {
  133.     "(", LPAREN, PAREN
  134.   },
  135.   {
  136.     ")", RPAREN, PAREN
  137.   },
  138.   {
  139.     0, 0, 0
  140.   }
  141. };
  142.  
  143.  
  144. char **ip;
  145. char *prog;
  146. struct op *ip_op;
  147.  
  148.  
  149. void syntax()
  150. {
  151.   write(2, prog, strlen(prog));
  152.   write(2, ": syntax error\n", 15);
  153.   exit(1);
  154. }
  155.  
  156.  
  157. long num(s)
  158. register char *s;
  159. {
  160.   long l = 0;
  161.   long sign = 1;
  162.  
  163.   while (*s == ' ' || *s == '\t') ++s;
  164.   if (*s == '\0') syntax();
  165.   if (*s == '-') {
  166.     sign = -1;
  167.     s++;
  168.   }
  169.   while (*s >= '0' && *s <= '9') l = l * 10 + *s++ - '0';
  170.   while (*s == ' ' || *s == '\t') ++s;
  171.   if (*s != '\0') syntax();
  172.   return(sign * l);
  173. }
  174.  
  175.  
  176. int filstat(nm, mode)
  177. char *nm;
  178. int mode;
  179. {
  180.   struct stat s;
  181.   struct sgttyb t;
  182.  
  183.   switch (mode) {
  184.       case FILRD:
  185.     return(access(nm, 4) == 0);
  186.       case FILWR:
  187.     return(access(nm, 2) == 0);
  188.       case FILND:
  189.     return(stat(nm, &s) == 0 && ((s.st_mode & S_IFMT) != S_IFDIR));
  190.       case FILID:
  191.     return(stat(nm, &s) == 0 && ((s.st_mode & S_IFMT) == S_IFDIR));
  192.       case FILGZ:
  193.     return(stat(nm, &s) == 0 && (s.st_size > 0L));
  194.       case FILTT:
  195.     return(ioctl((int) num(nm), TIOCGETP, &t) == 0);
  196.   }
  197. }
  198.  
  199.  
  200. int lex(s)
  201. register char *s;
  202. {
  203.   register struct op *op = ops;
  204.  
  205.   if (s == 0) return EOI;
  206.   while (op->op_text) {
  207.     if (strcmp(s, op->op_text) == 0) {
  208.         ip_op = op;
  209.         return(op->op_num);
  210.     }
  211.     op++;
  212.   }
  213.   ip_op = (struct op *) 0;
  214.   return(OPERAND);
  215. }
  216.  
  217.  
  218. int primary(n)
  219. int n;
  220. {
  221.   register char *opnd1, *opnd2;
  222.   int res;
  223.  
  224.   if (n == EOI) syntax();
  225.   if (n == UNEGN) return (!expr(lex(*++ip)));
  226.   if (n == LPAREN) {
  227.     res = expr(lex(*++ip));
  228.     if (lex(*++ip) != RPAREN) syntax();
  229.     return(res);
  230.   }
  231.   if (n == OPERAND) {
  232.     opnd1 = *ip;
  233.     (void) lex(*++ip);
  234.     if (ip_op && ip_op->op_type == BINOP) {
  235.         struct op *op = ip_op;
  236.  
  237.         if ((opnd2 = *++ip) == (char *) 0) syntax();
  238.  
  239.         switch (op->op_num) {
  240.             case STEQL:
  241.             return(strcmp(opnd1, opnd2) == 0);
  242.             case STNEQ:
  243.             return(strcmp(opnd1, opnd2) != 0);
  244.             case INTEQ:
  245.             return(num(opnd1) == num(opnd2));
  246.             case INTNE:
  247.             return(num(opnd1) != num(opnd2));
  248.             case INTGE:
  249.             return(num(opnd1) >= num(opnd2));
  250.             case INTGT:
  251.             return(num(opnd1) > num(opnd2));
  252.             case INTLE:
  253.             return(num(opnd1) <= num(opnd2));
  254.             case INTLT:
  255.             return(num(opnd1) < num(opnd2));
  256.         }
  257.     }
  258.     ip--;
  259.     return(strlen(opnd1) > 0);
  260.   }
  261.  
  262.   /* Unary expression */
  263.   if (ip_op->op_type != UNOP || *++ip == 0) syntax();
  264.   if (n == STZER) return (strlen(*ip) == 0);
  265.   if (n == STNZE) return (strlen(*ip) != 0);
  266.   return(filstat(*ip, n));
  267. }
  268.  
  269.  
  270. int bexpr(n)
  271. int n;
  272. {
  273.   int res;
  274.  
  275.   if (n == EOI) syntax();
  276.   res = primary(n);
  277.   if (lex(*++ip) == BAND) return(bexpr(lex(*++ip)) && res);
  278.   ip--;
  279.   return(res);
  280. }
  281.  
  282.  
  283. int expr(n)
  284. int n;
  285. {
  286.   int res;
  287.  
  288.   if (n == EOI) syntax();
  289.   res = bexpr(n);
  290.   if (lex(*++ip) == BOR) return(expr(lex(*++ip)) || res);
  291.   ip--;
  292.   return(res);
  293. }
  294.  
  295.  
  296. main(argc, argv)
  297. int argc;
  298. char **argv;
  299. {
  300.   if (argv[0][0] == '[' && argv[argc - 1][0] != ']') {
  301.     write(2, "test: ] missing\n", 16);
  302.     exit(1);
  303.   }
  304.   if (argv[0][0] == '[') argc--;
  305.  
  306.   if (argc == 1) exit(1);
  307.   prog = argv[0];
  308.   ip = &argv[1];
  309.   exit(!expr(lex(*ip)));
  310. }
  311.